﻿using LaunchAllaround.DesignPattern;
using LaunchAllaround.DesignPattern.MVC;
using Microsoft.Kinect;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LaunchAllaround.Engine
{

    public class Kinect : Model<Kinect>
    {
        //SINGLETON PART
        private static Kinect myself = new Kinect();
        public static Kinect Myself
        {
            get
            {
                return Kinect.myself;
            }
        }

        private Kinect()
        {
            this.model = new ModelImpl<Kinect>();
            this.AddView(new KinectStatusView(this));
            this.AddView(new KinectView(this));
            this.AddView(new HandPositionAnalyzer());
            KinectSensor.KinectSensors.StatusChanged += this.kinectsStatusChanged;
            this.EnumerateSensors();
            this.activateStreams();
        }
        /// ////////////////////////////

        //MODEL PART

        private ModelImpl<Kinect> model;

        public void AddView(View<Kinect> v)
        {
            this.model.AddView(v);
        }

        public Container<View<Kinect>> GetViews()
        {
            return this.model.GetViews();
        }

        public void ClearViews()
        {
            this.model.ClearViews();
        }

        public void RefreshViews(RefreshEvent<Kinect> ev)
        {
            this.model.RefreshViews(ev);
        }
        //////////////////////////////



        private KinectSensor sensor;
        public KinectSensor Sensor { get { return this.sensor; } }

        private void onFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            if (this.sensor != null && this.sensor.Status != KinectStatus.Disconnected)
            {
                this.RefreshViews(new RefreshFrames(this, e));
            }
            
        }

        private void kinectsStatusChanged(object sender, StatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case KinectStatus.Connected:
                    this.sensor = e.Sensor;
                    this.activateStreams();
                    this.sensor.AllFramesReady += this.onFramesReady;
                    this.Start();
                    break;
                
                default:
                    if (this.sensor != null)
                    {
                        this.sensor.AllFramesReady -= this.onFramesReady;
                        this.sensor.Stop();
                    }
                    break;
            }
            if (this.sensor == null)
            {
                this.sensor = KinectSensor.KinectSensors.First();
            }
            this.RefreshViews(new RefreshKinectStatus(this));
        }

        public void EnumerateSensors()
        {

            foreach (KinectSensor potentialKinect in KinectSensor.KinectSensors)
            {
                if (potentialKinect.Status == KinectStatus.Connected ||potentialKinect.Status == KinectStatus.NotReady)
                {
                    this.sensor = potentialKinect;
                    this.activateStreams();
                    this.sensor.AllFramesReady += this.onFramesReady;
                    this.Start();
                    break;
                }
            }
            this.RefreshViews(new RefreshKinectStatus(this));
        }

        public void activateStreams()
        {
            if (this.sensor != null)
            {
                this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                this.sensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);
                this.sensor.SkeletonStream.Enable();
            }
        }

        public void Start()
        {
            this.sensor.Start();
        }


        public void Stop()
        {
            this.sensor.Stop();
        }

        public KinectStatus Status
        {
                get 
                {
                    if (this.sensor != null)
                    {
                        return this.sensor.Status;
                    }
                    else
                    {
                        return KinectStatus.Disconnected;
                    }
                }
        }

    }
}